package com.ruoyi.law.annotation.handler;

import cn.hutool.json.JSONUtil;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.law.annotation.NoRepeatSubmit;
import com.ruoyi.law.enums.ReturnStrategyEnum;
import com.ruoyi.law.factory.StrategyTypeFactory;
import com.ruoyi.law.factory.inter.DataHandler;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 重复提交校验
 *
 * @author lie
 * @date 2023/10/16
 */
@Aspect
@Component
@Slf4j
public class NoRepeatSubmitHandler {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Autowired
    private StrategyTypeFactory strategyTypeFactory;

    @Around("@annotation(noRepeatSubmit)")
    public Object repeatSubmitIntercept(ProceedingJoinPoint joinPoint, NoRepeatSubmit noRepeatSubmit) throws Throwable {
        String loginUserId;
        try {
            loginUserId = SecurityUtils.getUserId() + "";
        } catch (Exception e) {
            loginUserId = "";
        }
        // 获取当前切面所设置的方法的类名、方法名、参数
        String className = joinPoint.getTarget().getClass().getName();
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        String methodName = method.getName();
        Object[] args = joinPoint.getArgs();
        String param = JSONUtil.toJsonStr(args);
        // 获取配置的参数
        long timeout = noRepeatSubmit.timeout();
        int limit = noRepeatSubmit.limit();
        String message = noRepeatSubmit.message();
        ReturnStrategyEnum returnStrategy = noRepeatSubmit.returnStrategy();

        String key = loginUserId + ":" + className + ":" + methodName + ":" + param;
        // 判断是否已经超过重复提交的限制时间
        Object value = redisTemplate.opsForValue().get(key);
        if (Objects.nonNull(value)) {
            log.info(" --- >> 防重提交：key -- {}", key);
            Map<String, Object> map = new HashMap<>(5);
            map.put("message", message);
            map.put("key", key);
            map.put("value", value);
            map.put("limit", limit);
            map.put("timeout", timeout);
            // 判断是哪种策略
            DataHandler handler = strategyTypeFactory.getDataHandler(returnStrategy);
            Object data = handler.handleData(map);
            if (Objects.nonNull(data)) {
                return data;
            }
        }
        Object o = joinPoint.proceed();
        if (Objects.isNull(value)) {
            redisTemplate.opsForValue().set(key, o, timeout, TimeUnit.SECONDS);
        }
        return o;
    }
}
